package com.woniuxy.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.woniuxy.entity.DTO.CommitDTO;
import com.woniuxy.entity.DTO.GoodsType;
import com.woniuxy.entity.Goods;
import com.woniuxy.entity.GoodsStoreCondition;
import com.woniuxy.entity.GoodsUnit;
import com.woniuxy.mapper.*;
import com.woniuxy.service.GoodsService;
import com.woniuxy.util.PageParam;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;

@Service
public class GoodsServiceImpl implements GoodsService {
    static final String QUERY_GOODS_PREFIX = "GOODSSERVICEIMPL:QUERY:GOODS"; // 查找商品
    static final String LOCK_THREAD = "LOCKTHREAD"; // 分布式线程锁
    @Resource
    private GoodsMapper goodsMapper;
    @Resource
    GoodsTypeFirstMapper goodsTypeFirstMapper;
    @Resource
    GoodsStoreConditionMapper goodsStoreConditionMapper;
    @Resource
    GoodsUnitMapper goodsUnitMapper;
    @Resource
    GoodsTypeSecondMapper goodsTypeSecondMapper;
    @Resource
    GoodsCommitMapper goodsCommitMapper;
    @Resource
    private RedisTemplate redisTemplateInit; //不写String则默认是Object, Object

    @Override
    public PageInfo<Goods> queryGoodsServer(PageParam<Goods> pageParam) { // 请求来自于后台管理端
        if (pageParam.getParam() == null) {
            //参数1：pageNum(当前页)  参数2：pageSize(每页多少条参数)
            PageHelper.startPage(pageParam.getPageNum(), pageParam.getPageSize());
            List<Goods> goods = goodsMapper.queryAllGoods();
            return new PageInfo<>(goods);
        } else {
            //参数1：pageNum(当前页)  参数2：pageSize(每页多少条参数)
            PageHelper.startPage(pageParam.getPageNum(), pageParam.getPageSize());
            List<Goods> goods = goodsMapper.queryGoodsByCondition(pageParam.getParam());
            return new PageInfo<>(goods);
        }
    }

    @Override
    public List<Goods> queryGoodsApp(Goods goods) { // 请求来自于客户端App
        //先在Redis缓存中查找
        //在Redis查询对象为数组的场合, 用Map保存, 再用Iterator遍历Map
        Map<String, Goods> goodsMap = redisTemplateInit.opsForHash().entries(QUERY_GOODS_PREFIX);
        Iterator<Map.Entry<String, Goods>> iterator = goodsMap.entrySet().iterator();
        List<Goods> goodsList = new ArrayList<>();
        while (iterator.hasNext()) {
            Map.Entry<String, Goods> nextGoods = iterator.next();
            goodsList.add(nextGoods.getValue());
        }
        if (!goodsList.isEmpty()) { //在缓存中找到了值
            return goodsList;
        } else { //缓存中没有，则去SQL中查找
            String uuid = null;
            try { //在SQL中查找需要加分布式锁
                uuid = UUID.randomUUID().toString();
                boolean isLocked = redisTemplateInit.opsForValue().setIfAbsent(LOCK_THREAD, uuid);
                if (isLocked) { //成功上锁
                    //业务代码
                    //从数据库中查到数据
                    goodsList = goodsMapper.queryGoodsByCondition(goods);
                    //放到Redis缓存中去
                    for (Goods goodsIndex : goodsList) {
                        redisTemplateInit.opsForHash().put(QUERY_GOODS_PREFIX, goodsIndex.getId() + "", goodsIndex);
                    }
                    return goodsList;
                } else {
                    return null;
                }
            } catch (Exception e) {
                throw new RuntimeException("查询商品信息出错: " + e.getMessage(), e);
            } finally {
                if (uuid.equals(redisTemplateInit.opsForValue().get(LOCK_THREAD))) {
                    //确保当前线程只能释放自己上的锁
                    redisTemplateInit.delete(LOCK_THREAD);
                }
            }
        }
    }

    @Override
    public void addGoods(Goods goods) {
        String uuid = null;
        try {
            // 加分布式锁
            uuid = UUID.randomUUID().toString();
            boolean isLocked = redisTemplateInit.opsForValue().setIfAbsent(LOCK_THREAD, uuid);
            if (isLocked) {
                // 先插入数据库
                goodsMapper.addGoods(goods);
                // 然后更新缓存
                redisTemplateInit.opsForHash().put(QUERY_GOODS_PREFIX, goods.getId() + "", goods);
            } else {
                throw new RuntimeException("获取锁失败，请重试");
            }
        } catch (Exception e) {
            throw new RuntimeException("添加商品出错: " + e.getMessage(), e);
        } finally {
            if (uuid != null && uuid.equals(redisTemplateInit.opsForValue().get(LOCK_THREAD))) {
                redisTemplateInit.delete(LOCK_THREAD);
            }
        }
    }

    @Override
    public PageInfo<GoodsType> queryGoodsType(PageParam<GoodsType> pageParam) {
        // 设置分页参数
        PageHelper.startPage(pageParam.getPageNum(), pageParam.getPageSize());
        List<GoodsType> goodsTypes;
        if (pageParam.getParam().getLevel() == null) { //不筛选层级时联合2次查询结果(UNION)
            goodsTypes = goodsTypeFirstMapper.queryGoodsTypeByCondition(pageParam.getParam());
        } else { //筛选层级时不联合查询结果
            goodsTypes = goodsTypeFirstMapper.queryGoodsTypeByConditionWithLevel(pageParam.getParam());
        }
        return new PageInfo<>(goodsTypes);
    }

    @Override
    public List<GoodsType> queryTypeToDropdownBox() {
        List<GoodsType> goodsTypes = goodsTypeFirstMapper.queryTypeToDropdownBox();
        return goodsTypes;
    }

    @Override
    public List<GoodsStoreCondition> queryStoreConditionToDropdownBox() {
        List<GoodsStoreCondition> goodsStoreConditionList =
                goodsStoreConditionMapper.queryStoreConditionToDropdownBox();
        return goodsStoreConditionList;
    }

    @Override
    public List<GoodsUnit> queryUnitToDropdownBox() {
        List<GoodsUnit> goodsUnitList = goodsUnitMapper.queryUnitToDropdownBox();
        return goodsUnitList;
    }

    @Override
    public boolean changeGoodsStatus(Integer id) {
        String uuid = null;
        try {
            uuid = UUID.randomUUID().toString();
            boolean isLocked = redisTemplateInit.opsForValue().setIfAbsent(LOCK_THREAD, uuid);
            if (isLocked) {
                // 先更新数据库
                Goods goods = goodsMapper.queryGoodsById(id);
                if (goods.getStatus() == 1) {
                    goods.setStatus(0);
                } else {
                    goods.setStatus(1);
                }
                goodsMapper.changeGoodsStatus(goods);

                // 更新缓存
                redisTemplateInit.opsForHash().put(QUERY_GOODS_PREFIX, id + "", goods);
                return true;
            } else {
                return false;
            }
        } catch (Exception e) {
            throw new RuntimeException("修改商品状态出错: " + e.getMessage(), e);
        } finally {
            if (uuid != null && uuid.equals(redisTemplateInit.opsForValue().get(LOCK_THREAD))) {
                redisTemplateInit.delete(LOCK_THREAD);
            }
        }
    }

    @Override
    public boolean updateGoods(Goods goods) {
        String uuid = null;
        try {
            uuid = UUID.randomUUID().toString();
            boolean isLocked = redisTemplateInit.opsForValue().setIfAbsent(LOCK_THREAD, uuid);
            if (isLocked) {
                // 先更新数据库
                goodsMapper.updateGoods(goods);

                // 更新缓存
                redisTemplateInit.opsForHash().put(QUERY_GOODS_PREFIX, goods.getId() + "", goods);
                return true;
            } else {
                return false;
            }
        } catch (Exception e) {
            throw new RuntimeException("更新商品出错: " + e.getMessage(), e);
        } finally {
            if (uuid != null && uuid.equals(redisTemplateInit.opsForValue().get(LOCK_THREAD))) {
                redisTemplateInit.delete(LOCK_THREAD);
            }
        }
    }

    @Override
    public Goods queryGoodsById(Integer id) {
        // 先从缓存中查找
        Goods goods = (Goods) redisTemplateInit.opsForHash().get(QUERY_GOODS_PREFIX, id + "");
        if (goods != null) {
            return goods;
        }

        // 缓存中没有，从数据库查询
        String uuid = null;
        try {
            uuid = UUID.randomUUID().toString();
            boolean isLocked = redisTemplateInit.opsForValue().setIfAbsent(LOCK_THREAD, uuid);
            if (isLocked) {
                goods = goodsMapper.queryGoodsById(id);
                if (goods != null) {
                    // 放入缓存
                    redisTemplateInit.opsForHash().put(QUERY_GOODS_PREFIX, id + "", goods);
                }
                return goods;
            } else {
                throw new RuntimeException("获取锁失败，请重试");
            }
        } catch (Exception e) {
            throw new RuntimeException("查询商品详情出错: " + e.getMessage(), e);
        } finally {
            if (uuid != null && uuid.equals(redisTemplateInit.opsForValue().get(LOCK_THREAD))) {
                redisTemplateInit.delete(LOCK_THREAD);
            }
        }
    }

    @Override
    public boolean updateGoodsType(GoodsType goodsType) {
        String uuid = null;
        try { //给整个更新接口加锁
            uuid = UUID.randomUUID().toString();
            boolean isLocked = redisTemplateInit.opsForValue().setIfAbsent(LOCK_THREAD, uuid);
            if (isLocked) { //成功上锁
                //执行业务逻辑
                if (goodsType.getLevel().equals("2")) {
                    goodsTypeSecondMapper.updateGoodsType(goodsType);
                } else {
                    goodsTypeFirstMapper.updateGoodsType(goodsType);
                }
                return true;
            } else { //没有获取到锁的线程
                return false;
            }
        } catch (Exception e) {
            throw new RuntimeException();
        } finally {
            if (uuid.equals(redisTemplateInit.opsForValue().get(LOCK_THREAD))) {
                //确保当前线程只能释放自己上的锁
                redisTemplateInit.delete(LOCK_THREAD);
            }
        }
    }

    @Override
    public void addGoodsType(GoodsType goodsType) {
        if (goodsType.getLevel().equals("2")) {
            goodsType.setNameSecond(goodsType.getCategoryName());
            goodsTypeSecondMapper.addGoodsTypeSecond(goodsType);
        } else {
            goodsType.setNameFirst(goodsType.getCategoryName());
            goodsTypeFirstMapper.addGoodsTypeFirst(goodsType);
        }
    }

    @Override
    public GoodsType queryGoodsTypeById(Integer id, String level) {
        if (level.equals("2")) {
            return goodsTypeSecondMapper.queryGoodsTypeById(id);
        } else {
            return goodsTypeFirstMapper.queryGoodsTypeById(id);
        }
    }

    @Override
    public List<GoodsType> queryGoodsTypeByFirst() { //分类信息界面的下拉框回显
        return goodsTypeFirstMapper.queryGoodsTypeByFirst();
    }

    @Override
    public int updateGoodsTypeStatus(GoodsType goodsType) { //单独的更新状态值方法(状态值需要验证关联表值)

        String uuid = null;
        try { //给整个修改状态值接口加锁
            uuid = UUID.randomUUID().toString();
            boolean isLocked = redisTemplateInit.opsForValue().setIfAbsent(LOCK_THREAD, uuid);
            if (isLocked) { //成功上锁
                //执行业务逻辑

                if (goodsType.getStatus() == 0) { //若前端传来的参数表明此次操作为停用分类, 则需要的逻辑判断是否允许修改
                    if (goodsType.getLevel().equals("1")) {
                        //前端传来的为一级分类
                        List<GoodsType> goodsTypeList =
                                goodsTypeFirstMapper.
                                        queryGoodsTypeCheckSecond(goodsType.getTypeFirstId()); //先查出数据库中真正的数据
                        if (!goodsTypeList.isEmpty()) { //验证此一级分类下是否有对应二级(是否为空)
                            //若有，判断对应二级分类是否启用
                            for (GoodsType type : goodsTypeList) {
                                if (type.getStatus() == 1) { //若其下二级分类为启用
                                    return 4031; //拒绝修改
                                }
                            }
                            goodsTypeFirstMapper.updateGoodsTypeStatus(goodsType); //否则, 允许修改
                            return 200;
                        } else { //此一级分类下没有对应二级分类
                            goodsTypeFirstMapper.updateGoodsTypeStatus(goodsType); //允许修改
                            return 200;
                        }
                    } else { //前端传来的为二级分类
                        List<Goods> goodsList =
                                goodsTypeSecondMapper.
                                        queryGoodsTypeCheckGoods(goodsType.getTypeSecondId()); //先查出数据库中真正的数据
                        if (!goodsList.isEmpty()) { //验证此二级分类下是否有对应商品
                            //若有，判断对应商品是否启用
                            for (Goods goods : goodsList) {
                                if (goods.getStatus() == 1) { //若其下二级分类为启用
                                    return 4031; //拒绝修改
                                }
                            }
                            goodsTypeSecondMapper.updateGoodsTypeStatus(goodsType); //否则, 允许修改
                            return 200;
                        } else { //此二级分类下没有对应商品
                            goodsTypeSecondMapper.updateGoodsTypeStatus(goodsType); //允许修改
                            return 200;
                        }
                    }
                } else {
                    if (goodsType.getLevel().equals("1")) { //前端传来的参数表明此次操作为启用分类, 允许修改
                        //前端传来的为一级分类
                        goodsTypeFirstMapper.updateGoodsTypeStatus(goodsType); //允许修改
                        return 200;
                    } else { //前端传来的为二级分类
                        goodsTypeSecondMapper.updateGoodsTypeStatus(goodsType); //允许修改
                        return 200;
                    }
                }
            } else { //没有获取到锁的线程
                return 4034;
            }
        } catch (Exception e) {
            throw new RuntimeException();
        } finally {
            if (uuid.equals(redisTemplateInit.opsForValue().get(LOCK_THREAD))) {
                //确保当前线程只能释放自己上的锁
                redisTemplateInit.delete(LOCK_THREAD);
            }
        }
    }

    @Override
    public List<CommitDTO> queryGoodsCommitByGoodsId(Integer goodsId) {
        return goodsCommitMapper.queryGoodsCommitByGoodsId(goodsId);
    }
}
